//
// Created by yunnan xu on 2021/1/1.
//

#include "ComputePass.h"
#include "Pass.h"
#include "Scene.h"
#include "RenderItem.h"
#include "ResourceMgr.h"
#include "Texture.h"
#include "DummyModel.h"
#include "Scene.h"
#include "Camera.h"
#include "Model.h"
#include "EngineCore.h"
#include "GLESUtils.h"
#include <EGL/egl.h>
#include <GLES3/gl32.h>
#include <memory>
#include "gtc/random.hpp"
#include "Buffer.h"

# define NUM_PARTICLES 81920
# define WORK_GROUP_SIZE 256
# define PARTICLE_LIFETIME 10

ComputePass<GraphicsAPI::GLESv3>::ComputePass()
{
    ParticleStructure * data = new ParticleStructure[NUM_PARTICLES];
    for (int i = 0; i < NUM_PARTICLES; ++i)
    {
          data[i].position = glm::vec4();
          data[i].velocity = glm::vec4(glm::sphericalRand(1.0f), 1.0f);
    }

    // 函数原型 long number, long each_size, const void * data
    rwBuffer = std::make_shared<RWBuffer<GraphicsAPI::GLESv3>>(NUM_PARTICLES, sizeof(ParticleStructure), data);
    spaceBuffer = std::make_shared<RWBuffer<GraphicsAPI::GLESv3>>(512 * 64 * 512, sizeof(unsigned int), nullptr); // 存放index

    delete[] data;
}

ComputePass<GraphicsAPI::GLESv3>::ComputePass(void * rwBufferData, uint32_t particleSize, uint32_t particleNum)
{
    rwBuffer = std::make_shared<RWBuffer<GraphicsAPI::GLESv3>>(particleNum, particleSize, rwBufferData);
}


std::shared_ptr<RWBuffer<GraphicsAPI::GLESv3>> ComputePass<GraphicsAPI::GLESv3>::GetBuffer()
{
    return rwBuffer;
}

void ComputePass<GraphicsAPI::GLESv3>::InitShaderUniformLocation()
{
    timestep_location = GL_CHECK(glGetUniformLocation(program, "timestep"));
}

void ComputePass<GraphicsAPI::GLESv3>::Draw()
{
    auto curr_scene = SceneMgr::GetInstance()->GetCurrentScene();
    double tick_time = curr_scene->GetElapsedTime();

    // Bind the compute program
    GL_CHECK(glUseProgram(program));

    // Set the radius uniform
    GL_CHECK(glUniform1f(timestep_location, (float)tick_time));
    GL_CHECK(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, rwBuffer->GetBuffer()));

    GL_CHECK(glDispatchCompute(NUM_PARTICLES / WORK_GROUP_SIZE, 1, 1));
    GL_CHECK(glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT));

    GL_CHECK(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0));
}